package bayes.classifier;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class NaiveBayes {

	private Map<String,Integer> firstClassMap;
	private Map<String,Integer> secondClassMap;
	private Map<String,Integer> testDocMap;
	private Map<String, NounProbability> nounTotalCntMap;
	private Set<String> nounList;
	private NounProbability classProbability;
	String firstClassName;
	String secondClassName;
	String testFileName;
	int fileCount;
	
	public NaiveBayes() {
		firstClassMap  = new HashMap<String,Integer>();
		secondClassMap = new HashMap<String,Integer>();
		testDocMap = new HashMap<String,Integer>();
		nounTotalCntMap = new HashMap<String, NounProbability>();
		nounList = new HashSet<String>();
		classProbability = new NounProbability();
	}
	
	public Map<String,Integer> getNounCount(File dir) throws Exception {
		Map<String, Integer> nounCntMap = new HashMap<String, Integer>();

		// We read each file in folders and get the nouns
		for (File inFile : dir.listFiles()) {
			fileCount++;
			//String fileN = inFile.getName().substring(0,inFile.getName().length() - 5);
			String line; 
			
			BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(inFile), "UTF-8"));
			
			// read characters
			while ((line = input.readLine()) != null)
			{
				int st = line.indexOf('[');
				int end = line.indexOf(']');
				if ((st > -1) && (end > -1) && (st < end)) {
					String stNew = line.substring((st + 1), end);

					if (stNew.equals("Noun")) {
						String noun = line.split("\\[")[0].split(" ")[line.split("\\[")[0].split(" ").length - 1];

						if (line.length() >= (end + 7))
						{	
							if (!line.substring((end + 3), (end + 7)).equals("Acro") &&
								!line.substring((end + 3),(end + 7)).equals("Prop") &&
								!line.substring((end + 3),(end + 7)).equals("Abbr"))
							{
								int count = nounCntMap.containsKey(noun) ? nounCntMap.get(noun) : 0;
								nounCntMap.put(noun, count + 1);
								nounList.add(noun);
							}
						}	
					}
				}
			}
			input.close();
		}
		return nounCntMap;
	}
	
	public void getFirstClass(File dir) throws Exception{
		fileCount = 0;
		firstClassMap = getNounCount(dir);
	    classProbability.setFirstClassCount(fileCount);
		firstClassName = dir.toString();
		System.out.println("FileCount 1="+fileCount);
	}
	
	public void getSecondClass(File dir) throws Exception{
		fileCount = 0;
		secondClassMap = getNounCount(dir);
		classProbability.setSecondClassCount(fileCount);
		secondClassName = dir.toString();
		System.out.println("FileCount 2="+fileCount);
	}
	
	public void learnBayes() { 
		Iterator<String> SetIterator = nounList.iterator();
	    while(SetIterator.hasNext()) {
	        String setElement = SetIterator.next();
	        NounProbability np = new NounProbability();
	        if (firstClassMap.containsKey(setElement) && secondClassMap.containsKey(setElement)) {
	        	np.setFirstClassCount(firstClassMap.get(setElement));
	        	np.setSecondClassCount(secondClassMap.get(setElement));
	        } else if (firstClassMap.containsKey(setElement)) {
	        	np.setFirstClassCount(firstClassMap.get(setElement));
	        	np.setSecondClassCount(0);
	        } else {
	        	np.setFirstClassCount(0);
	        	np.setSecondClassCount(secondClassMap.get(setElement));
	        }
	        np.setFirstClassCount(np.getFirstClassCount() + 1);
        	np.setSecondClassCount(np.getSecondClassCount() + 1);
	        nounTotalCntMap.put(setElement, np); 
	    }    	
	}
	
	public void getTestDoc(File inFile) throws Exception{
		testFileName = inFile.toString();
		String line; 
		BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(inFile), "UTF-8"));
		
		// read characters
		while ((line = input.readLine()) != null)
		{
			int st = line.indexOf('[');
			int end = line.indexOf(']');
			if ((st > -1) && (end > -1) && (st < end)) {
				String stNew = line.substring((st + 1), end);

				if (stNew.equals("Noun")) {
					String noun = line.split("\\[")[0].split(" ")[line.split("\\[")[0].split(" ").length - 1];

					if (line.length() >= (end + 7))
					{	
						if (!line.substring((end + 3), (end + 7)).equals("Acro") &&
							!line.substring((end + 3),(end + 7)).equals("Prop") &&
							!line.substring((end + 3),(end + 7)).equals("Abbr"))
						{
							int count = testDocMap.containsKey(noun) ? testDocMap.get(noun) : 0;
							testDocMap.put(noun, count + 1);
							System.out.println(noun + "--" + testDocMap.get(noun));
						}
					}	
				}
			}
		}
		input.close();
	}
	
	public String decideClass() {
		double condProb = 1.0;
		int power;
		String result;
		NounProbability np = new NounProbability();
		Iterator<Entry<String, Integer>> MapIterator = testDocMap.entrySet().iterator();
        while (MapIterator.hasNext()) {
	        Map.Entry pairs = (Map.Entry)MapIterator.next();
	        String nounName = pairs.getKey().toString();
	        np = nounTotalCntMap.get(nounName);
	        power = testDocMap.get(nounName);
	        condProb = condProb + 
	        		Math.log(Math.pow((double) np.getFirstClassCount()/ (double)np.getSecondClassCount(),power));
	        System.out.println(condProb);
        }   
        //condProb = condProb + Math.log(((double) classProbability.getFirstClassCount()/ (double) classProbability.getSecondClassCount()));

        Iterator<Entry<String, Integer>> MapAddIterator = testDocMap.entrySet().iterator();
        while (MapAddIterator.hasNext()) {
	        Map.Entry pairs = (Map.Entry)MapAddIterator.next();
	        String noun = pairs.getKey().toString();
	        np = nounTotalCntMap.get(noun);
	        if (condProb > 1.0) {
	        	int count = firstClassMap.containsKey(noun) ? firstClassMap.get(noun) : 0;
	        	firstClassMap.put(noun, count + np.getFirstClassCount());
	        	classProbability.setFirstClassCount(classProbability.getFirstClassCount() + np.getFirstClassCount());
	        } else {
	        	int count = secondClassMap.containsKey(noun) ? secondClassMap.get(noun) : 0;
	        	secondClassMap.put(noun, count + np.getSecondClassCount());
	        	classProbability.setSecondClassCount(classProbability.getSecondClassCount() + np.getSecondClassCount());
	        }
        }    

        if (condProb > 1.0) {
        	result = testFileName + ": Class :" + firstClassName + " with probability " + condProb;
        } else {
        	result = testFileName + ": Class :" + secondClassName + " with probability " + condProb;
        }	
		return result;
	}

	public NounProbability getClassProbability() {
		return classProbability;
	}

	public void setClassProbability(NounProbability classProbability) {
		this.classProbability = classProbability;
	}
}